<?php
declare(strict_types=1);

namespace ServerApp\lib\memory;

use ServerApp\lib\process_2\SProcess;
use Swoole\Channel;

/**
 * Class Chan
 * @package Tao\src\model\swoole
 */
class Chan
{
    /**
     * Chan constructor.
     */
    private function __construct()
    {
    }

    /**
     * @var Channel
     */
    private static $instance = [];

    /**
     * @var Channel
     */
    private $chan;
    private $name;

    /**
     * @param string $name
     * @param null $size
     * @return Chan
     */
    public static function getInstance(string $name = null, $size = null): Chan
    {
        $name = $name ?? "default";
        $size = $size ?? 1024 * 256;
        if (!(self::$instance[$name] ?? false)) {
            self::$instance[$name] = new self();
            self::$instance[$name]->chan = new Channel($size);
            self::$instance[$name]->name = $name;
        }
        return self::$instance[$name];
    }

    /**
     * @param int $max_count
     * @return mixed|string
     */
    public function pop($max_count = 100){
        $res = '';
        $count = 0;
        while (true) {
            $res = $this->chan->pop();
            if (!$res) {
                $count++;
                if ($count > $max_count) {
                    break;
                }
                usleep(500000);
                continue;
            } else {
                break;
            }
        }
        return $res;
    }

    /**
     * @param $data
     */
    public function push($data){
        while (true) {
            $res = $this->chan->push($data);
            if (!$res) {
                sleep(1);
                continue;
            } else {
                break;
            }
        }
    }

    private $listen_to_write_pid = 0;
    public $listen_to_write_path = '';

    public function listenToWrite($data = null, $path = null, $model = 'w') {
        if ($data) {
            $this->push($data);
        } else {
            $this->listen_to_write_path = $path ?? "/tmp/$this->name";
            $dir_name_arr = explode('/', $this->listen_to_write_path);
            array_pop($dir_name_arr);
            $dir_name = join('/', $dir_name_arr);
            if (!is_dir($dir_name)) {
                exec("mkdir -p $dir_name");
            }

            $this->listen_to_write_pid = (new SProcess(function ($p) use($model) {
                $fp = fopen($this->listen_to_write_path, $model);
                while (true) {
                    $data = $this->pop(1111111111);
                    if ($data) {
                        $fwrite_res = fwrite($fp, $data);
//                        var_dump('fwrite_res=' . var_export($fwrite_res, true));
                    } else {
//                        var_dump('kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk');
                        SProcess::kill($p->pid);
                    }
                }
            }, false, 0, $this->name . '_ltw'))->start();
        }
    }

    public function endListenToWrite($delete_file=true) {
        if ($this->listen_to_write_pid) {
            SProcess::kill($this->listen_to_write_pid);
            $this->listen_to_write_pid = 0;
        }
        if ($delete_file && $this->listen_to_write_path) {
            unlink($this->listen_to_write_path);
            $this->listen_to_write_path = '';
        }
    }
}
